home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2007 December / PCWKCD1207B.iso / Blogowanie poza sfera / Flock 1.0 beta / flock-1.0RC3.en-US.win32.exe / flock / components / nsPostUpdateWin.js < prev    next >
Text File  |  2007-10-18  |  22KB  |  722 lines

  1. /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
  2. /* ***** BEGIN LICENSE BLOCK *****
  3.  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  4.  *
  5.  * The contents of this file are subject to the Mozilla Public License Version
  6.  * 1.1 (the "License"); you may not use this file except in compliance with
  7.  * the License. You may obtain a copy of the License at
  8.  * http://www.mozilla.org/MPL/
  9.  *
  10.  * Software distributed under the License is distributed on an "AS IS" basis,
  11.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12.  * for the specific language governing rights and limitations under the
  13.  * License.
  14.  *
  15.  * The Original Code is the Update Service.
  16.  *
  17.  * The Initial Developer of the Original Code is Google Inc.
  18.  * Portions created by the Initial Developer are Copyright (C) 2005
  19.  * the Initial Developer. All Rights Reserved.
  20.  *
  21.  * Contributor(s):
  22.  *  Darin Fisher <darin@meer.net> (original author)
  23.  *
  24.  * Alternatively, the contents of this file may be used under the terms of
  25.  * either the GNU General Public License Version 2 or later (the "GPL"), or
  26.  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  27.  * in which case the provisions of the GPL or the LGPL are applicable instead
  28.  * of those above. If you wish to allow use of your version of this file only
  29.  * under the terms of either the GPL or the LGPL, and not to allow others to
  30.  * use your version of this file under the terms of the MPL, indicate your
  31.  * decision by deleting the provisions above and replace them with the notice
  32.  * and other provisions required by the GPL or the LGPL. If you do not delete
  33.  * the provisions above, a recipient may use your version of this file under
  34.  * the terms of any one of the MPL, the GPL or the LGPL.
  35.  *
  36.  * ***** END LICENSE BLOCK ***** */
  37.  
  38. /**
  39.  * This file contains an implementation of nsIRunnable, which may be invoked
  40.  * to perform post-update modifications to the windows registry and uninstall
  41.  * logs required to complete an update of the application.  This code is very
  42.  * specific to the xpinstall wizard for windows.
  43.  */
  44.  
  45. const URI_BRAND_PROPERTIES     = "chrome://branding/locale/brand.properties";
  46.  
  47. const KEY_APPDIR          = "XCurProcD";
  48. const KEY_TMPDIR          = "TmpD";
  49. const KEY_UPDROOT         = "UpdRootD";
  50. const KEY_UAPPDATA        = "UAppData";
  51.  
  52. // see prio.h
  53. const PR_RDONLY      = 0x01;
  54. const PR_WRONLY      = 0x02;
  55. const PR_APPEND      = 0x10;
  56.  
  57. const PERMS_FILE     = 0644;
  58. const PERMS_DIR      = 0700;
  59.  
  60. const nsIWindowsRegKey = Components.interfaces.nsIWindowsRegKey;
  61.  
  62. var gConsole = null;
  63. var gAppUpdateLogPostUpdate = false;
  64.  
  65. //-----------------------------------------------------------------------------
  66.  
  67. /**
  68.  * Console logging support
  69.  */
  70. function LOG(s) {
  71.   if (gAppUpdateLogPostUpdate) {
  72.     dump("*** PostUpdateWin: " + s + "\n");
  73.     gConsole.logStringMessage(s);
  74.   }
  75. }
  76.  
  77. /**
  78.  * This function queries the XPCOM directory service.
  79.  */
  80. function getFile(key) {
  81.   var dirSvc =
  82.       Components.classes["@mozilla.org/file/directory_service;1"].
  83.       getService(Components.interfaces.nsIProperties);
  84.   return dirSvc.get(key, Components.interfaces.nsIFile);
  85. }
  86.  
  87. /**
  88.  * Return the full path given a relative path and a base directory.
  89.  */
  90. function getFileRelativeTo(dir, relPath) {
  91.   var file = dir.clone().QueryInterface(Components.interfaces.nsILocalFile);
  92.   file.setRelativeDescriptor(dir, relPath);
  93.   return file;
  94. }
  95.  
  96. /**
  97.  * Creates a new file object given a native file path.
  98.  * @param   path
  99.  *          The native file path.
  100.  * @return  nsILocalFile object for the given native file path.
  101.  */
  102. function newFile(path) {
  103.   var file = Components.classes["@mozilla.org/file/local;1"]
  104.                        .createInstance(Components.interfaces.nsILocalFile);
  105.   file.initWithPath(path);
  106.   return file;
  107. }
  108.  
  109. /**
  110.  * This function returns a file input stream.
  111.  */
  112. function openFileInputStream(file) {
  113.   var stream =
  114.       Components.classes["@mozilla.org/network/file-input-stream;1"].
  115.       createInstance(Components.interfaces.nsIFileInputStream);
  116.   stream.init(file, PR_RDONLY, 0, 0);
  117.   return stream;
  118. }
  119.  
  120. /**
  121.  * This function returns a file output stream.
  122.  */
  123. function openFileOutputStream(file, flags) {
  124.   var stream =
  125.       Components.classes["@mozilla.org/network/file-output-stream;1"].
  126.       createInstance(Components.interfaces.nsIFileOutputStream);
  127.   stream.init(file, flags, 0644, 0);
  128.   return stream;
  129. }
  130.  
  131. //-----------------------------------------------------------------------------
  132.  
  133. const PREFIX_FILE = "File: ";
  134.  
  135. function InstallLogWriter() {
  136. }
  137. InstallLogWriter.prototype = {
  138.   _outputStream: null,  // nsIOutputStream to the install wizard log file
  139.  
  140.   /**
  141.    * Write a single line to the output stream.
  142.    */
  143.   _writeLine: function(s) {
  144.     s = s + "\r\n";
  145.     this._outputStream.write(s, s.length);
  146.   },
  147.  
  148.   /**
  149.    * This function creates an empty uninstall update log file if it doesn't
  150.    * exist and returns a reference to the resulting nsIFile.
  151.    */
  152.   _getUninstallLogFile: function() {
  153.     var file = getFile(KEY_APPDIR); 
  154.     file.append("uninstall");
  155.     if (!file.exists())
  156.       return null;
  157.  
  158.     file.append("uninstall.log");
  159.     if (!file.exists())
  160.       file.create(Components.interfaces.nsILocalFile.NORMAL_FILE_TYPE, PERMS_FILE);
  161.  
  162.     return file;
  163.   },
  164.  
  165.   /**
  166.    * Return the update.log file.  Use last-update.log file in case the
  167.    * updates/0 directory has already been cleaned out (see bug 311302).
  168.    */
  169.   _getUpdateLogFile: function() {
  170.     function appendUpdateLogPath(root) {
  171.       var file = root.clone();
  172.       file.append("updates");
  173.       file.append("0");
  174.       file.append("update.log");
  175.       if (file.exists())
  176.         return file;
  177.  
  178.       file = root; 
  179.       file.append("updates");
  180.       file.append("last-update.log");
  181.       if (file.exists())
  182.         return file;
  183.  
  184.       return null;
  185.     }
  186.  
  187.     // See the local appdata first if app dir is under Program Files.
  188.     var file = null;
  189.     try {
  190.       file = appendUpdateLogPath(getFile(KEY_UPDROOT));
  191.  
  192.       // When updating from Fx 2.0.0.1 to 2.0.0.3 (or later) on Vista,
  193.       // we will have to see also user app data (see bug 351949).
  194.       if (!file)
  195.         file = appendUpdateLogPath(getFile(KEY_UAPPDATA));
  196.     } catch (e) {
  197.     }
  198.  
  199.     // See the app dir if not found or app dir is out of Program Files.
  200.     if (!file)
  201.       file = appendUpdateLogPath(getFile(KEY_APPDIR));
  202.  
  203.     return file;
  204.   },
  205.  
  206.   /**
  207.    * Read update.log to extract information about files that were
  208.    * newly added for this update.
  209.    */
  210.   _readUpdateLog: function(logFile, entries) {
  211.     var stream;
  212.     try {
  213.       stream = openFileInputStream(logFile).
  214.           QueryInterface(Components.interfaces.nsILineInputStream);
  215.  
  216.       var line = {};
  217.       while (stream.readLine(line)) {
  218.         var data = line.value.split(" ");
  219.         if (data[0] == "EXECUTE" && data[1] == "ADD") {
  220.           // The uninstaller requires the path separator to be "\" and
  221.           // relative paths to start with a "\".
  222.           var relPath = "\\" + data[2].replace(/\//g, "\\");
  223.           entries[relPath] = null;
  224.         }
  225.       }
  226.     } finally {
  227.       if (stream)
  228.         stream.close();
  229.     }
  230.   },
  231.  
  232.   /**
  233.    * Read install_wizard log files to extract information about files that were
  234.    * previously added by the xpinstall installer and software update.
  235.    */
  236.   _readXPInstallLog: function(logFile, entries) {
  237.     var stream;
  238.     try {
  239.       stream = openFileInputStream(logFile).
  240.           QueryInterface(Components.interfaces.nsILineInputStream);
  241.  
  242.       function fixPath(path, offset) {
  243.         return path.substr(offset).replace(appDirPath, "");
  244.       }
  245.  
  246.       var appDir = getFile(KEY_APPDIR);
  247.       var appDirPath = appDir.path;
  248.       var line = {};
  249.       while (stream.readLine(line)) {
  250.         var entry = line.value;
  251.         // This works with both the entries from xpinstall (e.g. Installing: )
  252.         // and from update (e.g. installing: )
  253.         var searchStr = "nstalling: ";
  254.         var index = entry.indexOf(searchStr);
  255.         if (index != -1) {
  256.           entries[fixPath(entry, index + searchStr.length)] = null;
  257.           continue;
  258.         }
  259.  
  260.         searchStr = "Replacing: ";
  261.         index = entry.indexOf(searchStr);
  262.         if (index != -1) {
  263.           entries[fixPath(entry, index + searchStr.length)] = null;
  264.           continue;
  265.         }
  266.  
  267.         searchStr = "Windows Shortcut: ";
  268.         index = entry.indexOf(searchStr);
  269.         if (index != -1) {
  270.           entries[fixPath(entry + ".lnk", index + searchStr.length)] = null;
  271.           continue;
  272.         }
  273.       }
  274.     } finally {
  275.       if (stream)
  276.         stream.close();
  277.     }
  278.   },
  279.  
  280.   _readUninstallLog: function(logFile, entries) {
  281.     var stream;
  282.     try {
  283.       stream = openFileInputStream(logFile).
  284.           QueryInterface(Components.interfaces.nsILineInputStream);
  285.  
  286.       var line = {};
  287.       var searchStr = "File: ";
  288.       while (stream.readLine(line)) {
  289.         var index = line.value.indexOf(searchStr);
  290.         if (index != -1) {
  291.           var str = line.value.substr(index + searchStr.length);
  292.           entries.push(str);
  293.         }
  294.       }
  295.     } finally {
  296.       if (stream)
  297.         stream.close();
  298.     }
  299.   },
  300.  
  301.   /**
  302.    * This function initializes the log writer and is responsible for
  303.    * translating 'update.log' and the 'install_wizard' logs to the NSIS format.
  304.    */
  305.   begin: function() {
  306.     var updateLog = this._getUpdateLogFile();
  307.     if (!updateLog)
  308.       return;
  309.  
  310.     var newEntries = { };
  311.     this._readUpdateLog(updateLog, newEntries);
  312.  
  313.     try {
  314.       const nsIDirectoryEnumerator = Components.interfaces.nsIDirectoryEnumerator;
  315.       const nsILocalFile = Components.interfaces.nsILocalFile;
  316.       var prefixWizLog = "install_wizard";
  317.       var uninstallDir = getFile(KEY_APPDIR); 
  318.       uninstallDir.append("uninstall");
  319.       var entries = uninstallDir.directoryEntries.QueryInterface(nsIDirectoryEnumerator);
  320.       while (true) {
  321.         var wizLog = entries.nextFile;
  322.         if (!wizLog)
  323.           break;
  324.         if (wizLog instanceof nsILocalFile && !wizLog.isDirectory() &&
  325.             wizLog.leafName.indexOf(prefixWizLog) == 0) {
  326.           this._readXPInstallLog(wizLog, newEntries);
  327.           wizLog.remove(false);
  328.         }
  329.       }
  330.     }
  331.     catch (e) {}
  332.     if (entries)
  333.       entries.close();
  334.  
  335.     var uninstallLog = this._getUninstallLogFile();
  336.     var oldEntries = [];
  337.     this._readUninstallLog(uninstallLog, oldEntries);
  338.  
  339.     // Prevent writing duplicate entries in the log file
  340.     for (var relPath in newEntries) {
  341.       if (oldEntries.indexOf(relPath) != -1)
  342.         delete newEntries[relPath];
  343.     }
  344.  
  345.     if (newEntries.length == 0)
  346.       return;
  347.  
  348.     // since we are not running with elevated privs, we can't write out
  349.     // the log file (at least, not on Vista).  So, write the output to
  350.     // temp, and then later, we'll pass the file (gCopiedLog) to
  351.     // the post update clean up process, which can copy it to
  352.     // the desired location (because it will have elevated privs)
  353.     gCopiedLog = getFile(KEY_TMPDIR);
  354.     gCopiedLog.append("uninstall");
  355.     gCopiedLog.createUnique(gCopiedLog.DIRECTORY_TYPE, PERMS_DIR);
  356.     if (uninstallLog)
  357.       uninstallLog.copyTo(gCopiedLog, "uninstall.log");
  358.     gCopiedLog.append("uninstall.log");
  359.     
  360.     LOG("uninstallLog = " + uninstallLog.path);
  361.     LOG("copiedLog = " + gCopiedLog.path);
  362.     
  363.     if (!gCopiedLog.exists())
  364.       gCopiedLog.create(Components.interfaces.nsILocalFile.NORMAL_FILE_TYPE, 
  365.                         PERMS_FILE);
  366.       
  367.     this._outputStream =
  368.         openFileOutputStream(gCopiedLog, PR_WRONLY | PR_APPEND);
  369.  
  370.     // The NSIS uninstaller deletes all directories where the installer has
  371.     // added a file if the directory is empty after the files have been removed
  372.     // so there is no need to log directories.
  373.     for (var relPath in newEntries)
  374.       this._writeLine(PREFIX_FILE + relPath);
  375.   },
  376.  
  377.   end: function() {
  378.     if (!this._outputStream)
  379.       return;
  380.     this._outputStream.close();
  381.     this._outputStream = null;
  382.   }
  383. };
  384.  
  385. var installLogWriter;
  386. var gCopiedLog;
  387.  
  388. //-----------------------------------------------------------------------------
  389.  
  390. /**
  391.  * A thin wrapper around nsIWindowsRegKey
  392.  * note, only the "read" methods are exposed.  If you want to write
  393.  * to the registry on Vista, you need to be a priveleged app.
  394.  * We've moved that code into the uninstaller.
  395.  */
  396. function RegKey() {
  397.   // Internally, we may pass parameters to this constructor.
  398.   if (arguments.length == 3) {
  399.     this._key = arguments[0];
  400.     this._root = arguments[1];
  401.     this._path = arguments[2];
  402.   } else {
  403.     this._key =
  404.         Components.classes["@mozilla.org/windows-registry-key;1"].
  405.         createInstance(nsIWindowsRegKey);
  406.   }
  407. }
  408. RegKey.prototype = {
  409.   _key: null,
  410.   _root: null,
  411.   _path: null,
  412.  
  413.   ACCESS_READ:  nsIWindowsRegKey.ACCESS_READ,
  414.  
  415.   ROOT_KEY_CURRENT_USER: nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
  416.   ROOT_KEY_LOCAL_MACHINE: nsIWindowsRegKey.ROOT_KEY_LOCAL_MACHINE,
  417.   ROOT_KEY_CLASSES_ROOT: nsIWindowsRegKey.ROOT_KEY_CLASSES_ROOT,
  418.   
  419.   close: function() {
  420.     this._key.close();
  421.     this._root = null;
  422.     this._path = null;
  423.   },
  424.  
  425.   open: function(rootKey, path, mode) {
  426.     this._key.open(rootKey, path, mode);
  427.     this._root = rootKey;
  428.     this._path = path;
  429.   },
  430.  
  431.   openChild: function(path, mode) {
  432.     var child = this._key.openChild(path, mode);
  433.     return new RegKey(child, this._root, this._path + "\\" + path);
  434.   },
  435.  
  436.   readStringValue: function(name) {
  437.     return this._key.readStringValue(name);
  438.   },
  439.  
  440.   hasValue: function(name) {
  441.     return this._key.hasValue(name);
  442.   },
  443.  
  444.   hasChild: function(name) {
  445.     return this._key.hasChild(name);
  446.   },
  447.  
  448.   get childCount() {
  449.     return this._key.childCount;
  450.   },
  451.  
  452.   getChildName: function(index) {
  453.     return this._key.getChildName(index);
  454.   },
  455.  
  456.   toString: function() {
  457.     var root;
  458.     switch (this._root) {
  459.     case this.ROOT_KEY_CLASSES_ROOT:
  460.       root = "HKEY_KEY_CLASSES_ROOT";
  461.       break;
  462.     case this.ROOT_KEY_LOCAL_MACHINE:
  463.       root = "HKEY_LOCAL_MACHINE";
  464.       break;
  465.     case this.ROOT_KEY_CURRENT_USER:
  466.       root = "HKEY_CURRENT_USER";
  467.       break;
  468.     default:
  469.       LOG("unknown root key");
  470.       return "";
  471.     }
  472.     return root + "\\" + this._path;
  473.   }
  474. };
  475.  
  476. /**
  477.  * This method walks the registry looking for the registry keys of
  478.  * the previous version of the application.
  479.  */
  480. function haveOldInstall(key, brandFullName, version) {
  481.   var ourInstallDir = getFile(KEY_APPDIR);
  482.   var result = false;
  483.   var childKey, productKey, mainKey;
  484.   try {
  485.     for (var i = 0; i < key.childCount; ++i) {
  486.       var childName = key.getChildName(i);
  487.       childKey = key.openChild(childName, key.ACCESS_READ);
  488.       if (childKey.hasValue("CurrentVersion")) {
  489.         for (var j = 0; j < childKey.childCount; ++j) {
  490.           var productVer = childKey.getChildName(j); 
  491.           productKey = childKey.openChild(productVer, key.ACCESS_READ);
  492.           if (productKey.hasChild("Main")) {
  493.             mainKey = productKey.openChild("Main", key.ACCESS_READ);
  494.             var installDir = mainKey.readStringValue("Install Directory");
  495.             mainKey.close();
  496.             LOG("old install? " + installDir + " vs " + ourInstallDir.path);
  497.             LOG("old install? " + childName + " vs " + brandFullName);
  498.             LOG("old install? " + productVer.split(" ")[0] + " vs " + version);
  499.             if (newFile(installDir).equals(ourInstallDir) &&
  500.                 (childName != brandFullName ||
  501.                 productVer.split(" ")[0] != version)) {
  502.               result = true;
  503.             }
  504.           }
  505.           productKey.close();
  506.           if (result)
  507.             break;
  508.         }
  509.       }
  510.       childKey.close();
  511.       if (result)
  512.         break;
  513.     }
  514.   } catch (e) {
  515.     result = false;
  516.     if (childKey)
  517.       childKey.close();
  518.     if (productKey)
  519.       productKey.close();
  520.     if (mainKey)
  521.       mainKey.close();
  522.   }
  523.   return result;
  524. }
  525.  
  526. function checkRegistry()
  527. {
  528.   LOG("checkRegistry");
  529.  
  530.   var result = false;
  531.   
  532.   // Firefox is the only toolkit app that needs to do this. 
  533.   // return false for other applications.
  534.   var app = Components.classes["@mozilla.org/xre/app-info;1"].
  535.             getService(Components.interfaces.nsIXULAppInfo);
  536.   if (app.name == "Firefox") {          
  537.   try {
  538.     var key = new RegKey();
  539.     key.open(RegKey.prototype.ROOT_KEY_CLASSES_ROOT, "FirefoxHTML\\shell\\open\\command", key.ACCESS_READ);
  540.     var commandKey = key.readStringValue("");
  541.     LOG("commandKey = " + commandKey);
  542.     // if "-requestPending" is not found, we need to do the cleanup
  543.     result = (commandKey.indexOf("-requestPending") == -1);
  544.   } catch (e) {
  545.     LOG("failed to open command key for FirefoxHTML: " + e);
  546.   }
  547.   key.close();
  548.   }
  549.   return result;
  550. }
  551.  
  552. function checkOldInstall(rootKey, vendorShortName, brandFullName, version)
  553. {
  554.   var key = new RegKey();
  555.   var result = false;
  556.  
  557.   try {
  558.     key.open(rootKey, "SOFTWARE\\" + vendorShortName, key.ACCESS_READ);
  559.     LOG("checkOldInstall: " + key + " " + brandFullName + " " + version);
  560.     result = haveOldInstall(key, brandFullName, version);
  561.   } catch (e) {
  562.     LOG("failed trying to find old install: " + e);
  563.   }
  564.   key.close();
  565.   return result;
  566. }
  567.  
  568. //-----------------------------------------------------------------------------
  569.  
  570. function nsPostUpdateWin() {
  571.   gConsole = Components.classes["@mozilla.org/consoleservice;1"]
  572.                        .getService(Components.interfaces.nsIConsoleService);
  573.   var prefs = Components.classes["@mozilla.org/preferences-service;1"].
  574.               getService(Components.interfaces.nsIPrefBranch);
  575.   try {
  576.     gAppUpdateLogPostUpdate = prefs.getBoolPref("app.update.log.all");
  577.   }
  578.   catch (ex) {
  579.   }
  580.   try {
  581.     if (!gAppUpdateLogPostUpdate) 
  582.       gAppUpdateLogPostUpdate = prefs.getBoolPref("app.update.log.PostUpdate");
  583.   }
  584.   catch (ex) {
  585.   }
  586. }
  587.  
  588. nsPostUpdateWin.prototype = {
  589.   QueryInterface: function(iid) {
  590.     if (iid.equals(Components.interfaces.nsIRunnable) ||
  591.         iid.equals(Components.interfaces.nsISupports))
  592.       return this;
  593.     throw Components.results.NS_ERROR_NO_INTERFACE;
  594.   },
  595.  
  596.   run: function() {
  597.     // When uninstall/uninstall.update exists the uninstaller has already
  598.     // updated the uninstall.log with the files added by software update.
  599.     var updateUninstallFile = getFile(KEY_APPDIR); 
  600.     updateUninstallFile.append("uninstall");
  601.     updateUninstallFile.append("uninstall.update");
  602.     if (updateUninstallFile.exists()) {
  603.       LOG("nothing to do, uninstall.log has already been updated"); 
  604.       return;
  605.     }
  606.  
  607.     try {
  608.       installLogWriter = new InstallLogWriter();
  609.       try {
  610.         installLogWriter.begin();
  611.       } finally {
  612.         installLogWriter.end();
  613.         installLogWriter = null;
  614.       }
  615.     } catch (e) {
  616.       LOG(e);
  617.     } 
  618.     
  619.     var app =
  620.       Components.classes["@mozilla.org/xre/app-info;1"].
  621.         getService(Components.interfaces.nsIXULAppInfo).
  622.         QueryInterface(Components.interfaces.nsIXULRuntime);
  623.  
  624.     var sbs =
  625.       Components.classes["@mozilla.org/intl/stringbundle;1"].
  626.       getService(Components.interfaces.nsIStringBundleService);
  627.     var brandBundle = sbs.createBundle(URI_BRAND_PROPERTIES);
  628.  
  629.     var vendorShortName;
  630.     try {
  631.       // The Thunderbird vendorShortName is "Mozilla Thunderbird", but we
  632.       // just want "Thunderbird", so allow it to be overridden in prefs.
  633.  
  634.       var prefs =
  635.         Components.classes["@mozilla.org/preferences-service;1"].
  636.         getService(Components.interfaces.nsIPrefBranch);
  637.  
  638.       vendorShortName = prefs.getCharPref("app.update.vendorName.override");
  639.     }
  640.     catch (e) {
  641.       vendorShortName = brandBundle.GetStringFromName("vendorShortName");
  642.     }
  643.     var brandFullName = brandBundle.GetStringFromName("brandFullName");
  644.  
  645.     if (!gCopiedLog && 
  646.         !checkRegistry() &&
  647.         !checkOldInstall(RegKey.prototype.ROOT_KEY_LOCAL_MACHINE, 
  648.                          vendorShortName, brandFullName, app.version) &&
  649.         !checkOldInstall(RegKey.prototype.ROOT_KEY_CURRENT_USER, 
  650.                          vendorShortName, brandFullName, app.version)) {
  651.       LOG("nothing to do, so don't launch the helper");
  652.       return;
  653.     }
  654.  
  655.     try {
  656.       var winAppHelper = 
  657.         app.QueryInterface(Components.interfaces.nsIWinAppHelper);
  658.  
  659.       // note, gCopiedLog could be null
  660.       if (gCopiedLog)
  661.         LOG("calling postUpdate with: " + gCopiedLog.path);
  662.       else
  663.         LOG("calling postUpdate without a log");
  664.  
  665.       winAppHelper.postUpdate(gCopiedLog);
  666.     } catch (e) {
  667.       LOG("failed to launch the helper to do the post update cleanup: " + e); 
  668.     }
  669.   }
  670. };
  671.  
  672. //-----------------------------------------------------------------------------
  673.  
  674. var gModule = {
  675.   registerSelf: function(compMgr, fileSpec, location, type) {
  676.     compMgr = compMgr.QueryInterface(Components.interfaces.nsIComponentRegistrar);
  677.     
  678.     for (var key in this._objects) {
  679.       var obj = this._objects[key];
  680.       compMgr.registerFactoryLocation(obj.CID, obj.className, obj.contractID,
  681.                                       fileSpec, location, type);
  682.     }
  683.   },
  684.   
  685.   getClassObject: function(compMgr, cid, iid) {
  686.     if (!iid.equals(Components.interfaces.nsIFactory))
  687.       throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
  688.  
  689.     for (var key in this._objects) {
  690.       if (cid.equals(this._objects[key].CID))
  691.         return this._objects[key].factory;
  692.     }
  693.     
  694.     throw Components.results.NS_ERROR_NO_INTERFACE;
  695.   },
  696.   
  697.   _makeFactory: #1= function(ctor) {
  698.     function ci(outer, iid) {
  699.       if (outer != null)
  700.         throw Components.results.NS_ERROR_NO_AGGREGATION;
  701.       return (new ctor()).QueryInterface(iid);
  702.     } 
  703.     return { createInstance: ci };
  704.   },
  705.   
  706.   _objects: {
  707.     manager: { CID        : Components.ID("{d15b970b-5472-40df-97e8-eb03a04baa82}"),
  708.                contractID : "@mozilla.org/updates/post-update;1",
  709.                className  : "nsPostUpdateWin",
  710.                factory    : #1#(nsPostUpdateWin)
  711.              },
  712.   },
  713.   
  714.   canUnload: function(compMgr) {
  715.     return true;
  716.   }
  717. };
  718.  
  719. function NSGetModule(compMgr, fileSpec) {
  720.   return gModule;
  721. }
  722.